package org.mj.hz.http;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import lombok.Data;
import org.apache.commons.lang3.ClassUtils;
import org.mj.hz.annotation.MjRollback;
import org.mj.hz.config.MjRequestConfiguration;
import org.mj.hz.converter.json.MjFastjsonConverter;
import org.mj.hz.converter.xml.MjDom4jConverter;
import org.mj.hz.exception.MjParseAnnotationException;
import org.mj.hz.exception.MjRuntimeException;
import org.mj.hz.handler.MjHandlerChain;
import org.mj.hz.proxy.InterfaceProxyHandler;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@Data
public class MjMethod {

    static Log log = LogFactory.get();
    private InterfaceProxyHandler interfaceProxyHandler;

    private Method method;

    private BaseRequest baseRequest;

    /**
     * 降级对象
     */
    private  Object rollbackObject;

    /**
     * 请求配置
     */
    private MjRequestConfiguration requestConfiguration;



    public MjMethod(InterfaceProxyHandler interfaceProxyHandler, Method method,Class<?> interfaceClass
            , MjRequestConfiguration requestConfiguration) throws MjRuntimeException {
        this.interfaceProxyHandler = interfaceProxyHandler;
        this.method = method;
        this.requestConfiguration = requestConfiguration;
        baseRequest = new BaseRequest();
        analysisRollbackAnnotation(interfaceClass);
        analysisMethodAnnotation(method);
        analysisParamAnnotation(method);
    }

    /**
     * 解析rollback注解
     * @param interfaceClass
     */
    private void analysisRollbackAnnotation(Class<?> interfaceClass) {
        Annotation[] annotations = interfaceClass.getAnnotations();
        for (Annotation annotation : annotations) {
            if (StrUtil.equals(annotation.annotationType().getSimpleName(),MjRollback.class.getSimpleName())) {
                MjRollback mjRollback = (MjRollback) annotation;
                Class<?> aClass = mjRollback.rollbackClass();
                try {
                    Constructor<?> constructor = aClass.getConstructor();
                    rollbackObject = constructor.newInstance();
                } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }

                break;
            }
        }
    }

    /**
     * 解析方法注解 用于判断该参数是什么类型的
     *
     * @param method
     */

    private void analysisParamAnnotation(Method method) throws MjRuntimeException {

        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Annotation[] parameterAnnotations = parameter.getAnnotations();
            if (null != parameterAnnotations && parameterAnnotations.length > 0) { // 有对应注解
                if (parameterAnnotations.length > 1) {
                    throw new MjRuntimeException("不支持一个参数上 放置两个注解！");
                }
                for (Annotation annotation : parameterAnnotations) {
                    if (!MjHandlerChain.paramChain(baseRequest, annotation, i)) { // 解析失败
                        throw new MjParseAnnotationException(annotation);
                    }
                }
            } else {// 无对应注解
                if (ClassUtils.isPrimitiveOrWrapper(parameter.getType()) || parameter.getType().equals(String.class)) {// 默认for
                    baseRequest.getMjPreRequest().getParamMap().put(i, parameter.getName());
                }
            }
        }
    }


    /**
     * 处理参数注解
     *
     * @param method
     */
    private void analysisMethodAnnotation(Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            if (!MjHandlerChain.methodChain(baseRequest, annotation)) {
                throw new MjParseAnnotationException(annotation);
            }

        }
    }


    /**
     * 具体请求逻辑
     *
     * @param args
     * @return
     */
    public Object invoke(Object[] args) {
        HttpRequest httpRequest = baseRequest.makeRequest(args);
        log.info("请求类型：{}",httpRequest.getMethod().name());
        log.info("请求地址：{}", httpRequest.getUrl());
        log.info("请求头：{}", httpRequest.headers());
        log.info("请求体：{}", httpRequest.form());


        HttpResponse response = httpRequest.execute();
        Object res = null;
        if (response.isOk()) {
            String contentType = response.header("Content-Type");

            if (StrUtil.equals(contentType,ContentType.XML.getValue()) ||
                    StrUtil.equals(contentType,ContentType.TEXT_XML.getValue())) {
                res = requestConfiguration.getMjXmlConverter().deserialize(response.bodyBytes(),method.getReturnType());
            }else {
                res = requestConfiguration.getMjJsonConverter().deserialize(response.body().getBytes(),method.getReturnType());

            }
        } else {
            log.error("response : {}", response.body());
            throw new RuntimeException("请求失败！");

        }
        return res;
    }

}
